﻿// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/* Append.Enumerable.cs --
 * Ars Magna project, http://arsmagna.ru
 */

#nullable enable

namespace AM.Memory.Collections.Linq;

internal sealed class AppendExprEnumerable<T>
    : IPoolingEnumerable<T>
{
    private int _count;

    private IPoolingEnumerable<T>? _src;
    private T _element = default!;

    public AppendExprEnumerable<T> Init
        (
            IPoolingEnumerable<T> src,
            T element
        )
    {
        _src = src;
        _count = 0;
        _element = element;
        return this;
    }

    public IPoolingEnumerator<T> GetEnumerator()
    {
        _count++;
        return Pool<AppendExprEnumerator>.Get().Init
            (
                _src!.GetEnumerator(),
                this,
                _element
            );
    }

    private void Dispose()
    {
        if (_count == 0)
        {
            return;
        }

        _count--;
        if (_count == 0)
        {
            _src = default;
            _element = default!;
            Pool<AppendExprEnumerable<T>>.Return (this);
        }
    }

    internal class AppendExprEnumerator
        : IPoolingEnumerator<T>
    {
        private IPoolingEnumerator? _src;
        private AppendExprEnumerable<T>? _parent;
        private T _element = default!;
        private int _overcount;

        public AppendExprEnumerator Init
            (
                IPoolingEnumerator src,
                AppendExprEnumerable<T> parent,
                T element
            )
        {
            _src = src;
            _parent = parent;
            _element = element;
            _overcount = 0;
            return this;
        }

        public bool MoveNext()
        {
            if (!_src!.MoveNext())
            {
                if (_overcount == 0)
                {
                    _overcount++;
                    return true;
                }

                _overcount++;
                return false;
            }

            return true;
        }

        public void Reset()
        {
            _overcount = 0;
            _src!.Reset();
        }

        object IPoolingEnumerator.Current => Current!;

        public T Current => _overcount == 1 ? _element : (T)_src!.Current;

        public void Dispose()
        {
            _parent?.Dispose();
            _parent = null;
            _src?.Dispose();
            _src = default;
            Pool<AppendExprEnumerator>.Return (this);
        }
    }

    IPoolingEnumerator IPoolingEnumerable.GetEnumerator() => GetEnumerator();
}
